/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "stdint.h"
#include "os_obj.h"
#include "sys_task.h"
#include "bsp_api.h"

#include "nor_cmd.h"

#include "str_ext.h"
#include "common.h"

void nor_flash_opt(void);

#define GD25Q_CHIP_SIZE 2 * 1024 * 1024

struct
{
	uint16_t check_req;		// 0空闲 1-spi	2-qpi，地址范围 start~end
	uint16_t read_req;		// 0空闲 1-spi	2-qpi，地址范围 start~end
	uint16_t sig_read_req;
	uint16_t sig_write_req;
	uint16_t err;
	uint16_t inited;
	uint32_t dat;
	uint32_t dat_first;		// 数据递增起始值
	uint32_t addr;
	uint32_t addr_start;	// 扇区对齐
	uint32_t amount;		// 扇区对齐
	uint32_t tm_used;
	dword_tt *buff;
} nor;

/*-----------------------------------------------------------------------------------------------------*
* signal nor manage test
*-----------------------------------------------------------------------------------------------------*/
void nor_flash_demo(void)
{
	NOP1();
	
	if( 0 == (
	nor.check_req + 
	nor.read_req + 
	nor.sig_read_req + 
	nor.sig_write_req))
		return;
	
	if(0 == nor.inited)
	{
		nor.inited = 1;
		nor.addr_start = 0;
		nor.amount = 1* 1024 * 1024;
		nor.dat_first = 0x12345678;
	}
	
	nor.buff = malloc(4096+16);

	nor_flash_opt();

	free(nor.buff);
}

void nor_flash_opt(void)
{
	//spi mode check
	if (1 == nor.check_req)
	{
		// 写入数据
		uint32_t dats = nor.dat = nor.dat_first;

		flash_dbg_print("fix spi mode check : start \n");

		for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
		{
			if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
			{
				nor_sector_erase(nor.addr);
			}

			for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)
			{
				nor.buff[index].uVal = nor.dat++;
			}

			// 写入一页数据
			nor_write(nor.addr, SPI_NOR_PAGE_SIZE, nor.buff[0].v);

			if (0 == (nor.addr & 0x03FFFF))
			{
				flash_dbg_print("fix spi mode check write data: %d %% \n", nor.addr * 100 / GD25Q_CHIP_SIZE);
			}
		}

		// 读回校验
		nor.dat = dats;
		flash_dbg_print("fix spi mode check : read and check \n");
		for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
		{
			if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
			{
				// 读取一扇区数据
				nor_read(nor.addr, SPI_NOR_SECTOR_SIZE, nor.buff[0].v);

				for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
				{
					if (nor.buff[index].uVal != nor.dat)
					{
						nor.err++;
					}
					nor.dat++;
				}

				if (nor.err)
				{
					flash_dbg_print("fix spi mode check err: %d @ %x \n", nor.err, nor.addr);
					nor.err = 0;
				}
			}
		}

		nor.check_req = 0;
		flash_dbg_print("fix spi mode check : end \n");

		set_u32(nor.buff, 0, 4096 / 4);
	}

	//qpi mode check
	if (2 == nor.check_req)
	{
		// 写入数据
		uint32_t dats = nor.dat = nor.dat_first;
		flash_dbg_print("fix qpi mode check : start \n");

		//spi
		for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
		{
			if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
			{
				nor_sector_erase(nor.addr);
			}

			for (int index = 0; index < SPI_NOR_PAGE_SIZE / 4; index++)
			{
				nor.buff[index].uVal = nor.dat++;
			}

			// 写入一页数据
			nor_q_write(nor.addr, SPI_NOR_PAGE_SIZE, nor.buff[0].v);

			if (0 == (nor.addr & 0x03FFFF))
			{
				flash_dbg_print("fix qpi mode check write data: %d %% \n", nor.addr * 100 / GD25Q_CHIP_SIZE);
			}
		}

		nor.dat = dats;
		flash_dbg_print("fix qpi mode check : read and check \n");
		for (nor.addr = nor.addr_start; nor.addr < nor.amount + nor.addr_start; nor.addr += SPI_NOR_PAGE_SIZE)
		{
			if (nor.addr % SPI_NOR_SECTOR_SIZE == 0)
			{
				// 读取一扇区数据
				nor_q_read(nor.addr, SPI_NOR_SECTOR_SIZE, nor.buff[0].v);

				for (int index = 0; index < SPI_NOR_SECTOR_SIZE / 4; index++)
				{
					if (nor.buff[index].uVal != nor.dat)
					{
						nor.err++;
					}
					nor.dat++;
				}

				if (nor.err)
				{
					flash_dbg_print("fix spi mode check err: %d @ %x \n", nor.err, nor.addr);
					nor.err = 0;
				}
			}
		}
		flash_dbg_print("fix qpi mode check : end \n");
		nor.check_req = 0;

		set_u32(nor.buff, 0, 4096 / 4);
	}

	// 读数据 
	if (nor.read_req)
	{
		uint32_t addr, tm_start, addr_end;

		addr_end = nor.amount + nor.addr_start;
		tm_start = app_tick_get();

		for (addr = nor.addr_start; addr < addr_end; addr += 2048)
		{
			if (nor.read_req == 1)
				nor_read(addr, 2048, nor.buff[0].v);
			else
				nor_q_read(addr, 2048, nor.buff[0].v);
		}

		nor.tm_used = app_tick_get() - tm_start;

		nor.read_req = 0;
	}

	// 单读测试
	if (nor.sig_read_req)
	{
		memset(nor.buff, 0, 4096);

		if (nor.amount > 4096)
			nor.amount = 4096;

		if (nor.sig_read_req == 1)
			nor_read(nor.addr_start, nor.amount, &nor.buff[0].v[2]);
		else
			nor_q_read(nor.addr_start, nor.amount, &nor.buff[0].v[2]);

		nor.sig_read_req = 0;
	}

	// 单写测试
	if (nor.sig_write_req)
	{
		int cnt;

		nor_block_erase(nor.addr_start);

		if (nor.amount > 4096)
			nor.amount = 4096;

		for (cnt = 0; cnt < 1024; cnt++)
		{
			nor.buff[cnt].word.LW.uval = cnt * 2 + nor.dat_first;
			nor.buff[cnt].word.HW.uval = cnt * 2 + nor.dat_first + 1;
		}

		if (nor.sig_write_req == 1)
			nor_write_multi(nor.addr_start, nor.amount, &nor.buff[0].v[2]);
		else
			nor_q_write_multi(nor.addr_start, nor.amount, &nor.buff[0].v[2]);

		nor.sig_write_req = 0;
	}
}
